home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / langs / gst2gnu.lzh / GST2GNU.C next >
Encoding:
C/C++ Source or Header  |  1993-06-19  |  25.8 KB  |  764 lines

  1. /*****************************************************************************
  2.  * GST2GNU - Convert DRI and GST object modules to GNU-style a.out modules.
  3.  *
  4.  *          Wherever the term GST appears herein, it means either DRI-format
  5.  *          or GST-format object modules.  The only difference between the
  6.  *          two is that DRI has 8-char symbols, GST allows 22-char symbols.
  7.  *          We handle both types automatically.
  8.  *
  9.  *          GEMDOS file I/O and memory allocation is used, not because I
  10.  *          have anything against runtime libraries so much as that it
  11.  *          provides independence from size_t/int/long portability issues.
  12.  *
  13.  *          This file is self-contained; there are no other source modules
  14.  *          or header files other than standard compiler headers.  It was
  15.  *          written for HSC and syntax-checked during development with
  16.  *          MSDOS Borland C++ 3.1, and thus should compile fine on most
  17.  *          any compiler.
  18.  *
  19.  *          Don't let the appearance of the term 'GNU' fool you:  this is
  20.  *          public domain software, free of any encumbrances whatsoever.
  21.  *          There are no facist restrictions on copying or using this code
  22.  *          in any way you see fit.
  23.  *
  24.  * 06/16/93 v1.0 (Ian Lepore)
  25.  *          Created.
  26.  ****************************************************************************/
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdarg.h>
  32. #include <osbind.h>
  33.  
  34. #ifndef TRUE
  35.   #define TRUE  1
  36.   #define FALSE 0
  37. #endif
  38.  
  39. #ifdef __BORLANDC__     /* %@#!^@%#$@# Borland compiler won't define    */
  40.   #define __STDC__      /* __STDC__ unless you ask for Pure-ANSI mode.  */
  41. #endif                  /* (And nothing works right in its Pure-ANSI.)  */
  42.  
  43. #define MAXERRORS 15    /* stop trying after seeing this many reloc errors */
  44.  
  45. /*----------------------------------------------------------------------------
  46.  *  structures and constants used with a.out modules.
  47.  *    cobbled together from the manpage for a.out on a Sun system,
  48.  *    mainly by deleting massive amounts of unneeded (by me) stuff.
  49.  *--------------------------------------------------------------------------*/
  50.  
  51. typedef struct {                /* a.out module file header... */
  52.   unsigned long     a_info;     /* typical magic value identifies file */
  53.   unsigned long     a_text;     /* length of text, in bytes */
  54.   unsigned long     a_data;     /* length of data, in bytes */
  55.   unsigned long     a_bss;      /* length of uninitialized data area in bytes */
  56.   unsigned long     a_syms;     /* length of symbol table data in bytes */
  57.   unsigned long     a_entry;    /* start address (unused in object modules) */
  58.   unsigned long     a_trsize;   /* length of relocation info for text, in bytes */
  59.   unsigned long     a_drsize;   /* length of relocation info for data, in bytes */
  60. } EXEC;
  61.  
  62. #define A_OUT_MAGIC 0407        /* value of exec.a_info for object module */
  63.  
  64. typedef struct {                /* symbol for a.out file... */
  65.   long              n_strx;
  66.   unsigned char     n_type;
  67.   char              n_other;
  68.   short             n_desc;
  69.   unsigned long     n_value;
  70. } NLIST;
  71.  
  72. #define N_UNDF      0           /* symbol n_type flag values... */
  73. #define N_EXT       1
  74. #define N_ABS       2
  75. #define N_TEXT      4
  76. #define N_DATA      6
  77. #define N_BSS       8
  78. #define N_FN       15
  79. #define N_COMM     18
  80.  
  81. typedef struct {                /* reloc directive for a.out file... */
  82.   unsigned long     r_address;
  83.   unsigned long     r_symboldat;
  84. } RINFO;
  85.  
  86. #define RINFO_PCREL 0x80        /* values ORed into low byte of */
  87. #define RINFO_LONG  0x40        /* rinfo.r_symboldat */
  88. #define RINFO_WORD  0x20
  89. #define RINFO_EXT   0x10
  90.  
  91. /*----------------------------------------------------------------------------
  92.  * structures and constants used with GST modules.
  93.  *--------------------------------------------------------------------------*/
  94.  
  95. typedef struct {                /* GST module file header... */
  96.     short           magic;
  97.     long            tsize;
  98.     long            dsize;
  99.     long            bsize;
  100.     long            ssize;
  101.     long            stksize;
  102.     long            entry;
  103.     short           rlbflg;
  104. } GHEADER;
  105.  
  106. #define GMAGIC      0x601A
  107.  
  108. typedef struct {                /* symbol for GST file... */
  109.     char            name[8];
  110.     unsigned short  flags;
  111.     long            value;
  112. } GSYM;
  113.  
  114. #define GS_BSS         0x0100   /* GST symbol flags... */
  115. #define GS_TXT         0x0200
  116. #define GS_DAT         0x0400
  117. #define GS_EXTERN      0x0800
  118. #define GS_GLOBAL      0x2000
  119. #define GS_EQUATED     0x4000
  120. #define GS_DEFINED     0x8000
  121. #define GS_EXTENDED    0x0048   /* name extension block follows sym in file */
  122.  
  123. #define GR_ABS         0        /* GST relocation word values... */
  124. #define GR_DAT         1
  125. #define GR_TXT         2
  126. #define GR_BSS         3
  127. #define GR_EXT         4
  128. #define GR_UPPER       5
  129. #define GR_PCREL       6
  130. #define GR_FIRST       7
  131.  
  132. /*----------------------------------------------------------------------------
  133.  * internal structures and data.
  134.  *--------------------------------------------------------------------------*/
  135.  
  136. typedef struct {                    /* our internal-format symbol... */
  137.     char            name[24];
  138.     unsigned short  flags;
  139.     long            value;
  140. } SYM;
  141.  
  142. static GHEADER          inhdr;      /* GST module header */
  143. static SYM              *symtab;    /* internal-format symbol table */
  144. static unsigned short   *text;      /* GST module text segment contents */
  145. static unsigned short   *data;      /* GST module data segment contents */
  146. static unsigned short   *treloc;    /* GST module text relocation contents */
  147. static unsigned short   *dreloc;    /* GST module data relocation contents */
  148. static unsigned long    symcount;   /* number of symbols */
  149. static unsigned long    trcount;    /* number of text segment relocs */
  150. static unsigned long    drcount;    /* number of data segment relocs */
  151. static unsigned long    strtaboff;  /* cumulative index into string table */
  152. static unsigned short   errcount;   /* error counter */
  153.  
  154. /*----------------------------------------------------------------------------
  155.  * prototypes.
  156.  *--------------------------------------------------------------------------*/
  157.  
  158. #ifdef __STDC__
  159.   void fatal(char *,...);
  160.   void error(char *,...);
  161.   void gfree(void *);
  162.   void *emalloc(long);
  163.   void load_gst_header(short);
  164.   void load_gst_body(short);
  165.   void load_gst_symbols(short);
  166.   void load_gst_reloc(short);
  167.   long preprocess_relocs(unsigned short *,unsigned short *,long);
  168.   void load_gst_module(char *);
  169.   void write_unix_header(short,long,long,long);
  170.   void write_unix_body(short);
  171.   void write_unix_reloc(short,unsigned short *,long);
  172.   void write_unix_symbols(short);
  173.   void write_unix_stringtable(short);
  174.   void write_unix_module(char *);
  175.   int main(int,char **);
  176. #endif
  177.  
  178. /*----------------------------------------------------------------------------
  179.  * service routines.
  180.  *--------------------------------------------------------------------------*/
  181.  
  182. #ifdef __STDC__
  183.   static void fatal(char *fmt, ...)
  184. #else
  185.   static void fatal(fmt)
  186.     char *fmt;
  187. #endif
  188. /*****************************************************************************
  189.  * whine and die.
  190.  ****************************************************************************/
  191. {
  192.     va_list args;
  193.  
  194.     fputs("gst2gnu (fatal): ", stderr);
  195.     va_start(args, fmt);
  196.     vfprintf(stderr, fmt, args);
  197.     va_end(args);
  198.     fputc('\n', stderr);
  199.     exit(1);
  200. }
  201.  
  202. #ifdef __STDC__
  203.   static void error(char *fmt, ...)
  204. #else
  205.   static void error(fmt)
  206.     char *fmt;
  207. #endif
  208. /*****************************************************************************
  209.  * whine without dying unless we've seen MAXERRORS errors already.
  210.  ****************************************************************************/
  211. {
  212.     va_list args;
  213.  
  214.     fputs("gst2gnu (error): ", stderr);
  215.     va_start(args, fmt);
  216.     vfprintf(stderr, fmt, args);
  217.     va_end(args);
  218.     fputc('\n', stderr);
  219.  
  220.     ++errcount;
  221.  
  222.     if (errcount > MAXERRORS) {
  223.         fatal("too many errors; aborting");
  224.     }
  225. }
  226.  
  227. static void gfree(block)
  228.     void *block;
  229. /*****************************************************************************
  230.  * gentle-free; free the block if the pointer is non-NULL.
  231.  ****************************************************************************/
  232. {
  233.     if (block) {
  234.         Mfree(block);
  235.     }
  236. }
  237.  
  238. static void *emalloc(size)
  239.     long size;
  240. /*****************************************************************************
  241.  * allocate a block; whine and die if it fails.
  242.  ****************************************************************************/
  243. {
  244.     void *block;
  245.  
  246.     if (NULL == (block = (void*)Malloc(size))) {
  247.         fatal("out of memory, asked for %ld bytes", size);
  248.     }
  249.     return block;
  250. }
  251.  
  252. /*----------------------------------------------------------------------------
  253.  * routines for reading GST modules.
  254.  *--------------------------------------------------------------------------*/
  255.  
  256. static void load_gst_header(h)
  257.     short h;
  258. /*****************************************************************************
  259.  * load the input module header; whine and die if not a GST module.
  260.  ****************************************************************************/
  261. {
  262.     if (sizeof(GHEADER) != Fread(h, (long)sizeof(GHEADER), &inhdr)) {
  263.         fatal("error reading file header");
  264.     }
  265.  
  266.     if (inhdr.magic != GMAGIC) {
  267.         fatal("bad magic in file header (not a GST object module)");
  268.     }
  269.  
  270. }
  271.  
  272. static void load_gst_body(h)
  273.     short h;
  274. /*****************************************************************************
  275.  * the the text and data segments (if present) from the input module.
  276.  ****************************************************************************/
  277. {
  278.     if (inhdr.tsize != 0) {
  279.         text = emalloc(inhdr.tsize);
  280.         if (inhdr.tsize != Fread(h, inhdr.tsize, text)) {
  281.             fatal("error reading text segment");
  282.         }
  283.     }
  284.  
  285.     if (inhdr.dsize != 0) {
  286.         data = emalloc(inhdr.dsize);
  287.         if (inhdr.dsize != Fread(h, inhdr.dsize, data)) {
  288.             fatal("error reading data segment");
  289.         }
  290.     }
  291. }
  292.  
  293. static void load_gst_symbols(h)
  294.     short h;
  295. /*****************************************************************************
  296.  * load the symbols (if any) from the input module.
  297.  * converts both DRI and GST symbols to our internal format as it loads them.
  298.  ****************************************************************************/
  299. {
  300.     long    nsyms;
  301.     SYM     *cursym;
  302.     GSYM    gsym;
  303.  
  304.     symcount = 0;
  305.  
  306.     if (inhdr.ssize == 0) {
  307.         return;
  308.     }
  309.  
  310.     nsyms = inhdr.ssize / sizeof(GSYM);
  311.     symtab = emalloc(nsyms * sizeof(SYM));
  312.  
  313.     cursym = symtab;
  314.     while (nsyms) {
  315.         if (sizeof(GSYM) != Fread(h, (long)sizeof(GSYM), &gsym)) {
  316.             fatal("error reading symbol table");
  317.         }
  318.         --nsyms;
  319.         cursym->flags = gsym.flags;
  320.         cursym->value = gsym.value;
  321.         strncpy(cursym->name, gsym.name, 8);
  322.         cursym->name[8] = 0;
  323.         if ((gsym.flags & GS_EXTENDED) == GS_EXTENDED) {
  324.             if (sizeof(GSYM) != Fread(h, (long)sizeof(GSYM), &cursym->name[8])) {
  325.                 fatal("error reading symbol table");
  326.             }
  327.             --nsyms;
  328.             cursym->name[22] = 0;
  329.         }
  330.         ++cursym;
  331.         ++symcount;
  332.     }
  333. }
  334.  
  335. static void load_gst_reloc(h)
  336.     short h;
  337. /*****************************************************************************
  338.  * load the text and/or data relocation words from the input module.
  339.  ****************************************************************************/
  340. {
  341.     trcount = inhdr.tsize / 2;
  342.     drcount = inhdr.dsize / 2;
  343.  
  344.     if (inhdr.tsize != 0) {
  345.         treloc = emalloc(inhdr.tsize);
  346.         if (inhdr.tsize != Fread(h, inhdr.tsize, treloc)) {
  347.             fatal("error reading text-segment relocation info");
  348.         }
  349.     }
  350.  
  351.     if (inhdr.dsize != 0) {
  352.         dreloc = emalloc(inhdr.dsize);
  353.         if (inhdr.dsize != Fread(h, inhdr.dsize, dreloc)) {
  354.             fatal("error reading data-segment relocation info");
  355.         }
  356.     }
  357. }
  358.  
  359. static void load_gst_module(fname)
  360.     char *fname;
  361. /*****************************************************************************
  362.  * open the input file; call the functions which load it; close it.
  363.  ****************************************************************************/
  364. {
  365.     short   handle;
  366.  
  367.     if (0 > (handle = Fopen(fname, 0))) {
  368.         fatal("can't open input file %s", fname);
  369.     }
  370.  
  371.     load_gst_header(handle);
  372.     load_gst_body(handle);
  373.     load_gst_symbols(handle);
  374.     load_gst_reloc(handle);
  375.  
  376.     Fclose(handle);
  377.  
  378. }
  379.  
  380. /*----------------------------------------------------------------------------
  381.  * routines for converting/writing a.out modules.
  382.  *--------------------------------------------------------------------------*/
  383.  
  384. static void write_unix_header(h, nsyms, ntrelocs, ndrelocs)
  385.     short   h;
  386.     long    nsyms;
  387.     long    ntrelocs;
  388.     long    ndrelocs;
  389. /*****************************************************************************
  390.  * fill in and write the a.out file header.
  391.  ****************************************************************************/
  392. {
  393.     EXEC    outhdr;
  394.  
  395.     outhdr.a_info   = A_OUT_MAGIC;
  396.     outhdr.a_text   = inhdr.tsize;
  397.     outhdr.a_data   = inhdr.dsize;
  398.     outhdr.a_bss    = inhdr.bsize;
  399.     outhdr.a_syms   = nsyms    * sizeof(NLIST);
  400.     outhdr.a_trsize = ntrelocs * sizeof(RINFO);
  401.     outhdr.a_drsize = ndrelocs * sizeof(RINFO);
  402.     outhdr.a_entry  = 0;
  403.  
  404.     if (sizeof(EXEC) != Fwrite(h, (long)sizeof(EXEC), &outhdr)) {
  405.         fatal("error writing file header");
  406.     }
  407. }
  408.  
  409. static void write_unix_body(h)
  410.     short h;
  411. /*****************************************************************************
  412.  * write the text and/or data segments.
  413.  ****************************************************************************/
  414. {
  415.     if (inhdr.tsize != Fwrite(h, inhdr.tsize, text)) {
  416.         fatal("error writing text segment");
  417.     }
  418.  
  419.     if (inhdr.dsize != Fwrite(h, inhdr.dsize, data)) {
  420.         fatal("error writing data segment");
  421.     }
  422. }
  423.  
  424. static long preprocess_relocs(seg, relocs, count)
  425.     unsigned short  *seg;
  426.     unsigned short  *relocs;
  427.     long            count;
  428. /*****************************************************************************
  429.  * preprocess the GST reloc info before converting it to a.out format.
  430.  * this is called twice; once for the text seg and again for the data seg.
  431.  *
  432.  * some magical stuff happens here...
  433.  *
  434.  * first, we validate the existing relocation info as we cruise through it.
  435.  * this is mainly a debugging tool for me, in my work with other software
  436.  * which emits object modules.  (I can run modules through this program to
  437.  * validate them.)  But, it takes very little time to do since we have to
  438.  * walk the relocation words anyway, and it might help catch odd situations
  439.  * I didn't anticipate when the input module was created by non-HSC tools.
  440.  *
  441.  * in regards to conversion, we have to do some fixups in the text and data
  442.  * segments before we can convert the relocs to a.out format.  For a
  443.  * segment-relative fixup, a GST module contains a value in the data or
  444.  * text segment and the reloc directs the linker to add the base address of
  445.  * the appropriate segment at fixup time.  in an a.out module, the value in
  446.  * the text or data segment is relative to the base of the text segment, and
  447.  * the linker adds the base of the text segment at fixup time.  so, as we
  448.  * encounter data- or bss-relative fixup directives, we have to patch the
  449.  * value referred to in the text or data segment, to make it relative to
  450.  * the start of the text segment instead of the start of the segment the
  451.  * fixup refers to.
  452.  *
  453.  * and finally, not every GST reloc word turns into a corresponding
  454.  * a.out reloc directive, so as we walk the GST words we count up the
  455.  * ones that will result in an a.out reloc and return the total to the
  456.  * caller; these counts eventually end up in the a.out file header.
  457.  ****************************************************************************/
  458. {
  459.     int             is_long = FALSE;
  460.     unsigned short  rval;
  461.     long            *fixup;
  462.     long            nrelocs = 0;
  463.  
  464.     for (; count--; ++seg, ++relocs) {
  465.         rval = *relocs;
  466.         switch (rval & 0x0007) {
  467.  
  468.           case GR_UPPER:
  469.             if (is_long) {
  470.                 error("bad relocation - two longword markers in a row");
  471.             }
  472.             fixup   = (long *)seg;
  473.             is_long = TRUE;
  474.             break;
  475.  
  476.           case GR_ABS:
  477.             /* this needs no checking */
  478.             is_long = FALSE;
  479.             break;
  480.  
  481.           case GR_PCREL:
  482.             /* I don't know enough about this to handle it correctly */
  483.             fatal("can't handle pc-relative relocation directives");
  484.             break;
  485.  
  486.           case GR_FIRST:
  487.             if (is_long) {
  488.                 error("bad relocation - 32-bit fixup of 16-bit instruction word");
  489.             }
  490.             is_long = FALSE;
  491.             break;
  492.  
  493.           case GR_BSS:
  494.             if (!is_long) {
  495.                error("bad relocation - 16-bit bss-segment-relative fixup");
  496.             }
  497.             if (*fixup < 0 || *fixup > inhdr.bsize) {
  498.                 error("bad relocation - bss-relative fixup is outside bss segment");
  499.             }
  500.             *fixup += inhdr.tsize + inhdr.dsize;
  501.             ++nrelocs;
  502.             is_long = FALSE;
  503.             break;
  504.  
  505.           case GR_DAT:
  506.             if (!is_long) {
  507.                error("bad relocation - 16-bit data-segment-relative fixup");
  508.             }
  509.             if (*fixup < 0 || *fixup > inhdr.dsize) {
  510.                 error("bad relocation - data-relative fixup is outside data segment");
  511.             }
  512.             *fixup += inhdr.tsize;
  513.             ++nrelocs;
  514.             is_long = FALSE;
  515.             break;
  516.  
  517.           case GR_TXT:
  518.             if (!is_long) {
  519.                error("bad relocation - 16-bit text-segment-relative fixup");
  520.             }
  521.             if (*fixup < 0 || *fixup > inhdr.tsize) {
  522.                 error("bad relocation - text-relative fixup is outside data segment");
  523.             }
  524.             ++nrelocs;
  525.             is_long = FALSE;
  526.             break;
  527.  
  528.           case GR_EXT:
  529.             if ((rval >> 3) >= symcount) {
  530.                 error("bad relocation - reference to symbol # %d; only %ld symbols in file",
  531.                         (rval >> 3), symcount);
  532.             }
  533.             ++nrelocs;
  534.             is_long = FALSE;
  535.             break;
  536.         }
  537.         if ((rval & 0x0007) != GR_EXT && (rval >> 3) != 0) {
  538.             error("bad relocation - symbol index found in non-symbol fixup command");
  539.         }
  540.     }
  541.     return nrelocs;
  542. }
  543.  
  544. static long write_unix_reloc(h, relocs, count)
  545.     short           h;
  546.     unsigned short *relocs;
  547.     long            count;
  548. /*****************************************************************************
  549.  * write the a.out relocation directives.
  550.  * this is called twice; once for the text seg and again for the data seg.
  551.  ****************************************************************************/
  552. {
  553.     unsigned long   i;
  554.     unsigned short  rval;
  555.     unsigned long   symnum;
  556.     RINFO           rinfo;
  557.     unsigned short  symtyp = RINFO_WORD;
  558.     unsigned long   nrelocs = 0;
  559.  
  560.     for (i = 0; i < count; ++i) {
  561.         rval = *relocs++;
  562.         switch (rval & 0x0007) {
  563.  
  564.           case GR_UPPER:
  565.             symtyp = RINFO_LONG;    /* no output; just remember that the   */
  566.             continue;               /* next reloc is a longword operation. */
  567.  
  568.           case GR_PCREL:            /* (pc-rel filtered out by preproc)     */
  569.           case GR_ABS:
  570.           case GR_FIRST:
  571.             symtyp = RINFO_WORD;    /* no output; just reset to shortword   */
  572.             continue;               /* operation and get next reloc.        */
  573.  
  574.           case GR_BSS:
  575.             symnum = N_BSS;
  576.             break;
  577.  
  578.           case GR_DAT:
  579.             symnum = N_DATA;
  580.             break;
  581.  
  582.           case GR_TXT:
  583.             symnum = N_TEXT;
  584.             break;
  585.  
  586.           case GR_EXT:
  587.             symnum  = rval >> 3;
  588.             symtyp |= RINFO_EXT;
  589.             break;
  590.         }
  591.         rinfo.r_address   = (symtyp & RINFO_LONG) ? i*2 - 2 : i*2;
  592.         rinfo.r_symboldat = (symnum << 8) | symtyp;
  593.         if (sizeof(RINFO) != Fwrite(h, (long)sizeof(RINFO), &rinfo)) {
  594.             fatal("error writing relocation info");
  595.         }
  596.         ++nrelocs;
  597.         symtyp = RINFO_WORD;
  598.     }
  599.     return nrelocs;
  600. }
  601.  
  602. static void write_unix_symbols(h)
  603.     short h;
  604. /*****************************************************************************
  605.  * write the non-string part of the a.out symbol table.
  606.  *
  607.  * we keep track of offsets into the 'string table' part of the module as
  608.  * we go, but we don't actually build up a string table in memory. we just
  609.  * walk our internal symbol table, converting and dumping the non-string
  610.  * parts of each symbol as we go.  symbols defined in the input module in
  611.  * the data or bss segments have to be adjusted so that their values are
  612.  * relative to the start of the text segment.  (really, one starts to wonder
  613.  * why a.out files have any notion of segments at all. ::grin::)
  614.  ****************************************************************************/
  615. {
  616.     unsigned long   i;
  617.     NLIST           nlist;
  618.     SYM             *cursym;
  619.  
  620.     strtaboff = 4;      /* string table offset starts at 4 */
  621.  
  622.     for (i = 0, cursym = symtab; i < symcount; ++i, ++cursym) {
  623.         nlist.n_other = 0;
  624.         nlist.n_desc  = 0;
  625.         nlist.n_strx  = strtaboff;
  626.         nlist.n_value = cursym->value;
  627.         switch (cursym->flags & (GS_TXT|GS_DAT|GS_BSS|GS_EQUATED)) {
  628.           default:
  629.             nlist.n_type   = N_UNDF;
  630.             break;
  631.           case GS_EQUATED:
  632.             nlist.n_type   = N_ABS;
  633.             break;
  634.           case GS_TXT:
  635.             nlist.n_type   = N_TEXT;
  636.             break;
  637.           case GS_DAT:
  638.             nlist.n_type   = N_DATA;
  639.             nlist.n_value += inhdr.tsize;
  640.             break;
  641.           case GS_BSS:
  642.             nlist.n_type   = N_BSS;
  643.             nlist.n_value += inhdr.tsize + inhdr.dsize;
  644.             break;
  645.         }
  646.         if (cursym->flags & (GS_EXTERN|GS_GLOBAL)) {
  647.             nlist.n_type |= N_EXT;
  648.         }
  649.         if (sizeof(NLIST) != Fwrite(h, (long)sizeof(NLIST), &nlist)) {
  650.             fatal("error writing symbol table");
  651.         }
  652.         strtaboff += strlen(cursym->name) + 1;
  653.     }
  654. }
  655.  
  656. static void write_unix_stringtable(h)
  657.     short h;
  658. /*****************************************************************************
  659.  * write the a.out symbol string table.
  660.  *
  661.  * the first longword in the string table is the size of the string table,
  662.  * including the longword size value itself.  since we didn't bother to
  663.  * build an in-memory string table, we just walk our internal symbol table
  664.  * again; this time dumping only the string part of each symbol.
  665.  ****************************************************************************/
  666. {
  667.     unsigned long   i;
  668.     unsigned long   len;
  669.     SYM             *cursym;
  670.  
  671.     if (sizeof(strtaboff) != Fwrite(h, (long)sizeof(strtaboff), &strtaboff)) {
  672.         fatal("error writing string table");
  673.     }
  674.  
  675.     for (i = 0, cursym = symtab; i < symcount; ++i, ++cursym) {
  676.         len = 1 + strlen(cursym->name);
  677.         if (len != Fwrite(h, len, cursym->name)) {
  678.             fatal("error writing string table");
  679.         }
  680.     }
  681. }
  682.  
  683. static void write_unix_module(fname)
  684.     char *fname;
  685. /*****************************************************************************
  686.  * open output file; call conversion/output routines; close file.
  687.  ****************************************************************************/
  688. {
  689.     short   handle;
  690.     long    ntrelocs;
  691.     long    ndrelocs;
  692.  
  693.     ntrelocs = preprocess_relocs(text, treloc, trcount);
  694.     ndrelocs = preprocess_relocs(data, dreloc, drcount);
  695.  
  696.     if (errcount != 0) {
  697.         fatal("relocation errors encountered; aborting");
  698.     }
  699.  
  700.     if (0 > (handle = Fcreate(fname, 0))) {
  701.         fatal("can't create output file %s", fname);
  702.     }
  703.  
  704.     write_unix_header(handle, symcount, ntrelocs, ndrelocs);
  705.     write_unix_body(handle);
  706.  
  707.     if (ntrelocs != write_unix_reloc(handle, treloc, trcount)) {
  708.         fatal("internal error - didn't write proper number of text relocs");
  709.     }
  710.  
  711.     if (ndrelocs != write_unix_reloc(handle, dreloc, drcount)) {
  712.         fatal("internal error - didn't write proper number of data relocs");
  713.     }
  714.  
  715.     write_unix_symbols(handle);
  716.     write_unix_stringtable(handle);
  717.  
  718.     if (0 != Fclose(handle)) {
  719.         fatal("error close output file");
  720.     }
  721.  
  722.     gfree(text);
  723.     gfree(data);
  724.     gfree(treloc);
  725.     gfree(dreloc);
  726.     gfree(symtab);
  727. }
  728.  
  729. int main(argc, argv)
  730.     int  argc;
  731.     char **argv;
  732. /*****************************************************************************
  733.  * a typical simplistic main routine.
  734.  ****************************************************************************/
  735. {
  736.     char *in_name;
  737.     char *out_name;
  738.  
  739.     switch (argc) {
  740.       default:
  741.         fputs("usage: GST2GNU infile [outfile]\n"
  742.               "       if outfile not specified, infile is overwritten.\n"
  743.               "\n"
  744.               "Converts a DRI or GST object module to an a.out module\n"
  745.               "which can be used with the GNU LD linker and other tools.\n"
  746.               , stderr);
  747.         exit(1);
  748.       case 2:
  749.         in_name  = argv[1];
  750.         out_name = argv[1];
  751.         break;
  752.       case 3:
  753.         in_name  = argv[1];
  754.         out_name = argv[2];
  755.         break;
  756.     }
  757.  
  758.     load_gst_module(in_name);
  759.     write_unix_module(out_name);
  760.  
  761.     return 0;
  762.  
  763. }
  764.